﻿using System;
using System.Collections.Generic;
using System.Linq;

using Autodesk.AutoCAD.ApplicationServices;
using AcRx = Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.DatabaseServices.Filters;
using Autodesk.AutoCAD.EditorInput;
using System.Windows.Media.Converters;
using Autodesk.AutoCAD.Colors;


namespace DonetArxLib
{
    class UtilFunc
    {
        public static string AddLineToCurrentSpace(Point3d start, Point3d end, string layerName = null)
        {
            string handle = string.Empty;
            var db = HostApplicationServices.WorkingDatabase;
            using (var trans = db.TransactionManager.StartTransaction())
            {
                var modelSpace = trans.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;

                using (var line = new Line(start, end))
                {
                    if (!string.IsNullOrEmpty(layerName))
                    {
                        EnsureLayerExist(db, layerName, 3, true);
                        line.Layer = layerName;
                        line.ColorIndex = 256;
                    }

                    modelSpace.AppendEntity(line);
                    trans.AddNewlyCreatedDBObject(line, true);
                    handle = line.Handle.ToString();
                }

                trans.Commit();
            }

            return handle;
        }

        public static ObjectId AddLineToModelSpace(Point3d start, Point3d end, string layerName = null)
        {
            ObjectId id = ObjectId.Null;
            var db = HostApplicationServices.WorkingDatabase;
            using (var trans = db.TransactionManager.StartTransaction())
            {
                var blockTable = GetObject(trans, db.BlockTableId, OpenMode.ForRead) as BlockTable;
                if (blockTable == null)
                    return id;

                var modelSpace = GetObject(trans, blockTable["*Model_Space"], OpenMode.ForWrite) as BlockTableRecord;
                if (modelSpace == null)
                    return id;

                using (var line = new Line(start, end))
                {
                    if (!string.IsNullOrEmpty(layerName))
                    {
                        EnsureLayerExist(db, layerName, 3, true);
                        line.Layer = layerName;
                        line.ColorIndex = 256;
                    }

                    id = modelSpace.AppendEntity(line);
                    trans.AddNewlyCreatedDBObject(line, true);
                }

                trans.Commit();
            }

            return id;
        }

        public static string AddTextToCurrentSpace(Point3d position, string content, double textHeight)
        {
            string handle = string.Empty;
            var db = HostApplicationServices.WorkingDatabase;
            using (var trans = db.TransactionManager.StartTransaction())
            {
                var modelSpace = trans.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;

                using (var text = new DBText())
                {
                    text.TextString = content;
                    text.Height = textHeight;
                    text.Position = position;
                    text.ColorIndex = 256;

                    modelSpace.AppendEntity(text);
                    trans.AddNewlyCreatedDBObject(text, true);
                    handle = text.Handle.ToString();
                }

                trans.Commit();
            }

            return handle;
        }

        public static void AddToCurrentSpace(Entity entity, Transaction trans, string layerName = null)
        {
            if (entity == null)
                throw new ArgumentNullException(nameof(entity));

            var db = HostApplicationServices.WorkingDatabase;
            var modelSpace = trans.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;
            if (!string.IsNullOrEmpty(layerName))
                entity.Layer = layerName;

            modelSpace.AppendEntity(entity);
            trans.AddNewlyCreatedDBObject(entity, true);
        }

        public static void EnsureLayerExist(Database db, string layerName, short colorIndex = 1, bool createIfNotExist = true)
        {
            using (var trans = db.TransactionManager.StartTransaction())
            {
                var layerTable = trans.GetObject(db.LayerTableId, OpenMode.ForRead) as LayerTable;
                if (layerTable.Has(layerName))
                    return;

                using (var layer = new LayerTableRecord())
                {
                    layer.Name = layerName;
                    layer.Color = Autodesk.AutoCAD.Colors.Color.FromColorIndex(Autodesk.AutoCAD.Colors.ColorMethod.Foreground, colorIndex);
                    trans.GetObject(db.LayerTableId, OpenMode.ForWrite);
                    layerTable.Add(layer);
                    trans.AddNewlyCreatedDBObject(layer, true);
                }

                trans.Commit();
            }
        }

        public static double GetCurDbExtern()
        {
            var obj1 = Autodesk.AutoCAD.ApplicationServices.Core.Application.GetSystemVariable("extmin");
            var obj2 = Autodesk.AutoCAD.ApplicationServices.Core.Application.GetSystemVariable("extmax");

            if (obj1 == null || obj2 == null)
                return -1;

            var ptMin = (Point3d)obj1;
            var ptMax = (Point3d)obj2;

            var pt1 = new Point3d(ptMin.X, ptMin.Y, 0);
            var pt2 = new Point3d(ptMax.X, ptMax.Y, 0);

            return pt1.DistanceTo(pt2);
        }

        public static bool RenameLayer(string oldName, string newName, Database db)
        {
            using (var trans = db.TransactionManager.StartTransaction())
            {
                var layerTable = GetObject(trans, db.LayerTableId, OpenMode.ForRead) as LayerTable;
                if (!layerTable.Has(oldName))
                    return false;

                if (layerTable.Has(newName))
                    return false;

                var layerId = layerTable[oldName];
                var layer = GetObject(trans, layerId, OpenMode.ForWrite) as LayerTableRecord;
                if (layer == null)
                    return false;


                layer.Name = newName;
                trans.Commit();
            }

            return true;
        }

        public static DBObject GetObject(Transaction trans, ObjectId id, OpenMode openMode, System.Exception ex = null)
        {
            try
            {
                return trans.GetObject(id, openMode, false);
            }
            catch (System.Exception e)
            {
                ex = e;
                return null;
            }
        }

        public static double GetTextHeight()
        {
            var db = HostApplicationServices.WorkingDatabase;
            var heights = new List<double>();

            using (var trans = db.TransactionManager.StartTransaction())
            {
                var bt = trans.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                if (bt == null)
                    return -1;

                var modelSpace = trans.GetObject(bt["*Model_Space"], OpenMode.ForRead) as BlockTableRecord;
                if (modelSpace == null)
                    return -1;

                GetTextHeightInBTR(modelSpace, trans, heights);

            }

            if (heights.Count < 1)
                return -1;

            heights.Sort();
            if (heights.Count < 5)  // 不到5个，取平均值
                return heights.Average();
            else                    // 否则取前 4/5 的平均值
            {
                int count5 = heights.Count / 5 * 4;

                double total = 0;
                for (int i = 0; i < count5; i++)
                    total += heights[i];

                if (total < 0)
                    return -1;

                return total / count5;
            }

        }

        private static void GetTextHeightInBTR(BlockTableRecord btr, Transaction trans, List<double> heights)
        {
            var brs = new List<BlockReference>();

            foreach (var id in btr)
            {
                if (heights.Count > 1000)
                    break;


                var obj = GetObject(trans, id, OpenMode.ForRead);
                if (obj == null)
                    continue;

                if (obj is DBText dbt && dbt.Height > 0.0000001)
                    heights.Add(dbt.Height);
                else if (obj is MText mt && mt.TextHeight > 0.0000001)
                    heights.Add(mt.TextHeight);
                else if (obj is BlockReference br)
                    brs.Add(br);
            }

            if (heights.Count < 1000)
            {
                foreach (var br in brs)
                {
                    if (heights.Count < 1000)
                        GetTextHeightsInBlock(br, heights);
                }
            }
        }

        private static void GetEntitiesTextHeight(DBObjectCollection entities, List<double> heights)
        {
            foreach (var obj in entities)
            {
                if (heights.Count > 1000)
                    break;

                if (obj is DBText dbt && dbt.Height > 0.0000001)
                    heights.Add(dbt.Height);
                else if (obj is MText mt && mt.Height > 0.0000001)
                    heights.Add(mt.TextHeight);
                else if (obj is BlockReference br)
                    GetTextHeightsInBlock(br, heights);
            }
        }

        private static void GetTextHeightsInBlock(BlockReference br, List<double> heights)
        {
            DBObjectCollection objects = new DBObjectCollection();
            if (br.BlockId == ObjectId.Null)
                return;

            try
            {
                br.Explode(objects);
                GetEntitiesTextHeight(objects, heights);
            }
            catch
            {

            }
        }

        public static void ChangeTextStyle(List<string> existFonts, string fontFileName, string bigFontFileName)
        {
            var db = HostApplicationServices.WorkingDatabase;
            using (var trans = db.TransactionManager.StartTransaction())
            {
                var tst = trans.GetObject(db.TextStyleTableId, OpenMode.ForWrite) as TextStyleTable;
                foreach (var tstrid in tst)
                {
                    var tstr = GetObject(trans, tstrid, OpenMode.ForWrite) as TextStyleTableRecord;
                    if (tstr == null)
                        continue;

                    //if (!existFonts.Contains(tstr.FileName.ToLower()) && !existFonts.Contains(tstr.FileName.ToLower() + ".shx"))
                    //tstr.FileName = "txt.shx";
                    tstr.FileName = fontFileName;

                    //if (string.IsNullOrEmpty(tstr.BigFontFileName) || 
                    //    (!existFonts.Contains(tstr.BigFontFileName.ToLower()) && !existFonts.Contains(tstr.BigFontFileName.ToLower() + ".shx")))
                    tstr.BigFontFileName = bigFontFileName;
                    //tstr.BigFontFileName = "gbcbig.shx";
                }

                trans.Commit();
            }
        }

        public static void SetOleObjectPlotStyle()
        {
            var db = HostApplicationServices.WorkingDatabase;
            var btrId = db.CurrentSpaceId;
            using (var trans = db.TransactionManager.StartTransaction())
            {
                var btr = trans.GetObject(btrId, OpenMode.ForRead) as BlockTableRecord;
                foreach (var id in btr)
                {
                    if (GetObject(trans, id, OpenMode.ForWrite) is Ole2Frame ole)
                    {
                        ole.OutputQuality = 1;      // 0:单色 1:低质量 2:高质量 3:自动设置
                    }
                }

                trans.Commit();
            }
        }

        public static void IterateAllLayers(ObjectId lineTypeID)
        {
            var db = HostApplicationServices.WorkingDatabase;
            using (var trans = db.TransactionManager.StartTransaction())
            {
                var lt = trans.GetObject(db.LayerTableId, OpenMode.ForRead) as LayerTable;
                foreach (var layerId in lt)
                {
                    try
                    {
                        var layer = GetObject(trans, layerId, OpenMode.ForWrite) as LayerTableRecord;

                        if (layer != null)
                        {
                            layer.IsLocked = false;
                            if (layer.LineWeight == LineWeight.ByLineWeightDefault || ((int)layer.LineWeight < 20 && (int)layer.LineWeight > 0))
                                layer.LineWeight = LineWeight.LineWeight000;

                            if (lineTypeID != ObjectId.Null)
                                layer.LinetypeObjectId = lineTypeID;

                            if (!layer.IsPlottable)
                                layer.IsPlottable = true;
                        }
                    }
                    catch (System.Exception)
                    {
                    }
                }
                trans.Commit();
            }
        }

        public static ObjectId GetContinueLineTypeID()
        {
            using (var trans = HostApplicationServices.WorkingDatabase.TransactionManager.StartTransaction())
            {
                var lineTypeTable = trans.GetObject(HostApplicationServices.WorkingDatabase.LinetypeTableId, OpenMode.ForRead) as LinetypeTable;
                if (lineTypeTable != null)
                {
                    if (lineTypeTable.Has("Continuous"))
                        return lineTypeTable["Continuous"];
                }
            }

            return ObjectId.Null;
        }

        public static void IterateDB(bool deleteAllHatch = false)
        {
            var db = HostApplicationServices.WorkingDatabase;
            using (var trans = db.TransactionManager.StartTransaction())
            {
                var bt = trans.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                foreach (var btrId in bt)
                {
                    var btr = trans.GetObject(btrId, OpenMode.ForWrite) as BlockTableRecord;
                    foreach (var entityId in btr)
                    {
                        var obj = GetObject(trans, entityId, OpenMode.ForWrite);
                        if (obj == null || obj.IsErased)
                            continue;

                        // 干掉链接
                        if (obj is Entity ent)
                        {
                            var hlc = ent.Hyperlinks;
                            for (int i = 0; i < hlc.Count; i++)
                                hlc.RemoveAt(0);
                        }

                        switch (obj)
                        {
                            case Ole2Frame ole:
                                ole.OutputQuality = 0;
                                break;
                            case MText mt:
                                try
                                {
                                    DBObjectCollection dbc = new DBObjectCollection();
                                    mt.Explode(dbc);
                                    mt.Erase();

                                    foreach (DBObject dbo in dbc)
                                    {
                                        var entity = dbo as Entity;
                                        if (entity != null)
                                        {
                                            btr.AppendEntity(entity);
                                            trans.AddNewlyCreatedDBObject(entity, true);
                                        }
                                    }
                                }
                                catch { }
                                break;
                            case Hatch hc:
                                if (deleteAllHatch)
                                    hc.Erase();
                                else if (hc.IsGradient)  // 处理渐变hatch填充
                                    hc.Erase();
                                break;
                            case Wipeout wp:
                                wp.Erase();
                                break;
                            default:
                                break;
                        }
                    }
                }

                trans.Commit();
            }
        }

        public static void IterateBlocksInBlockTable(Func<ObjectId, Transaction, bool> iterFunc, bool isCommit = false)
        {
            var db = HostApplicationServices.WorkingDatabase;
            using (var trans = db.TransactionManager.StartTransaction())
            {
                var bt = trans.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                foreach (var btrId in bt)
                {
                    if (!iterFunc(btrId, trans))
                        break;
                }

                if (isCommit)
                    trans.Commit();
                else
                    trans.Abort();
            }
        }

        public static void IterateEntitiesInBlock(ObjectId idBlk, Func<ObjectId, Transaction, bool> iterFunc, Transaction trans)
        {
            var btr = trans.GetObject(idBlk, OpenMode.ForWrite) as BlockTableRecord;
            foreach (var entityId in btr)
            {
                if (!iterFunc(entityId, trans))
                    break;
            }
        }

        public static void IterateEntitiesInModelSpace(Func<ObjectId, bool> iterFunc, Transaction trans = null, Database db = null)
        {
            if (db == null)
                db = HostApplicationServices.WorkingDatabase;

            if (trans == null)
                trans = GetTopTransation();

            if (trans == null)
                throw new ArgumentNullException("no transaction!");

            var blockTable = GetObject(trans, db.BlockTableId, OpenMode.ForRead) as BlockTable;
            if (blockTable == null)
                throw new InvalidOperationException("no blocktable found!");

            var modelSpace = GetObject(trans, blockTable["*Model_Space"], OpenMode.ForWrite) as BlockTableRecord;
            if (modelSpace == null)
                throw new InvalidOperationException("no model space found!");

            foreach (var entityId in modelSpace)
            {
                if (!iterFunc(entityId))
                    break;
            }
        }

        public static void IterateEntitiesInBlock(string blockName, Func<ObjectId, Transaction, bool> iterFunc, Database db = null)
        {
            if (db == null)
                db = HostApplicationServices.WorkingDatabase;

            using (var trans = db.TransactionManager.StartTransaction())
            {
                var blkTbl = trans.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                if (blkTbl.Has(blockName))
                {
                    var blk = trans.GetObject(blkTbl[blockName], OpenMode.ForRead) as BlockTableRecord;
                    if (blk == null)
                        return;

                    foreach (var entityId in blk)
                        if (!iterFunc(entityId, trans))
                            break;
                }
            }
        }

        public static void GetTextExtern()
        {
            var db = HostApplicationServices.WorkingDatabase;
            using (var trans = db.TransactionManager.StartTransaction())
            {
                var blkRcd = trans.GetObject(db.CurrentSpaceId, OpenMode.ForRead) as BlockTableRecord;
                if (blkRcd == null)
                    return;

                foreach (var id in blkRcd)
                {
                    if (id.IsErased || !id.IsWellBehaved)
                        continue;

                    var entity = trans.GetObject(id, OpenMode.ForRead);
                    if (entity == null)
                        continue;


                }

                trans.Commit();
            }
        }

        public static void DrawExten(Extents3d ext)
        {
            if (ext != null)
                AddLineToCurrentSpace(ext.MinPoint, ext.MaxPoint, "testline");
        }

        public static bool CaptureDocumentImage(Document doc, string filePathName)
        {
            try
            {
                var bitmap = doc.CapturePreviewImage(1024, 768);
                bitmap.Save(filePathName, System.Drawing.Imaging.ImageFormat.Jpeg);
                return true;
            }
            catch (System.Exception)
            {
                return false;
            }
        }

        public static Transaction GetTopTransation()
        {
            var doc = Application.DocumentManager.MdiActiveDocument;
            if (doc == null)
                throw new ArgumentNullException("no document!");

            var trans = doc.TransactionManager.TopTransaction;
            if (trans == null)
                throw new AcRx.Exception(AcRx.ErrorStatus.NoActiveTransactions);

            return trans;
        }

        public static bool IsLayoutActived(string layoutName)
        {
            var db = HostApplicationServices.WorkingDatabase;
            using (var trans = db.TransactionManager.StartTransaction())
            {
                var layoutDict = trans.GetObject(db.LayoutDictionaryId, OpenMode.ForRead) as DBDictionary;
                if (layoutDict == null)
                    throw new System.Exception("invalid layout dictionary!");

                if (layoutDict.Contains(layoutName))
                {
                    var layoutID = layoutDict.GetAt(layoutName);
                    var layout = trans.GetObject(layoutID, OpenMode.ForRead) as Layout;
                    if (layout == null)
                        return true;

                    int count = 0;
                    if (layout.BlockTableRecordId.IsValid)
                    {
                        var blk = GetObject(trans, layout.BlockTableRecordId, OpenMode.ForRead) as BlockTableRecord;
                        if (blk == null)
                            return false;

                        foreach (var entityId in blk)
                            count++;
                    }

                    return count > 0;
                }
            }

            return true;
        }

        public static void ModifyPreference()
        {
            dynamic app = Application.AcadApplication;
            dynamic files = app.Preferences.Files;
            string path2 = files.SupportPath;       // 搜索支持路径
            string pc3Path = files.PrinterConfigPath;  // 打印机搜索路径 pc3
            string pmpPath = files.PrinterDescPath; // pmp 搜索路径
            string stbctbPath = files.PrinterStyleSheetPath; // *.stb, *.ctb 搜索路径

            //可以直接赋值，多个路径用封号 ; 隔开。
        }

        public static ObjectId Handle2ID(string handle, Database db)
        {
            if (string.IsNullOrEmpty(handle)) throw new ArgumentException("handle");
            if (db == null) throw new ArgumentNullException("db");

            long lnum = Convert.ToInt64(handle, 16);
            if (lnum == 0L)
                return ObjectId.Null;

            return db.GetObjectId(false, new Handle(lnum), 1);
        }

        /// <summary>
        /// xclip 命令的自定义实现
        /// </summary>
        /// <param name="db"></param>
        /// <param name="pt1"></param>
        /// <param name="pt2"></param>
        /// <param name="idBlkRef"></param>
        public static void XClipBlockReference(Database db, Point3d pt1, Point3d pt2, ObjectId idBlkRef)
        {
            const string filterDictName = "ACAD_FILTER";
            const string spatialName = "SPATIAL";

            using (var trans = db.TransactionManager.StartTransaction())
            {
                var br = UtilFunc.GetObject(trans, idBlkRef, OpenMode.ForRead) as BlockReference;

                pt1 = pt1.TransformBy(br.BlockTransform.Inverse());
                pt2 = pt2.TransformBy(br.BlockTransform.Inverse()); pt1.ToPoint2d();

                Point2d rectMin = new Point2d(Math.Min(pt1.X, pt2.X), Math.Min(pt1.Y, pt2.Y));
                Point2d rectMax = new Point2d(Math.Max(pt1.X, pt2.X), Math.Max(pt1.Y, pt2.Y));

                Point2dCollection pts = new Point2dCollection(2) { rectMin, rectMax };
                SpatialFilter sf = new SpatialFilter { Definition = new SpatialFilterDefinition(pts, Vector3d.ZAxis, double.PositiveInfinity, double.NegativeInfinity, 0.0, true) };

                if (br.ExtensionDictionary == ObjectId.Null)
                {
                    br.UpgradeOpen();
                    br.CreateExtensionDictionary();
                    br.DowngradeOpen();
                }

                DBDictionary xDict = UtilFunc.GetObject(trans, br.ExtensionDictionary, OpenMode.ForWrite) as DBDictionary;
                if (xDict.Contains(filterDictName))
                {
                    DBDictionary fDict = UtilFunc.GetObject(trans, xDict.GetAt(filterDictName), OpenMode.ForWrite) as DBDictionary;
                    if (fDict.Contains(spatialName))
                        fDict.Remove(spatialName);

                    fDict.SetAt(spatialName, sf);
                }
                else
                {
                    DBDictionary fDict = new DBDictionary();
                    xDict.SetAt(filterDictName, fDict);
                    trans.AddNewlyCreatedDBObject(fDict, true);
                    fDict.SetAt(spatialName, sf);
                }

                trans.AddNewlyCreatedDBObject(sf, true);

                trans.Commit();
            }
        }

        /// <summary>
        /// 在当前活动空间插入OLE图片对象
        /// </summary>
        /// <param name="imgPath"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="direction"></param>
        /// <param name="isCountersign"></param>
        public static void InsertImageOle(string imgPath, double x, double y, double width, double height, int direction, bool isCountersign = false)
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            using (System.Drawing.Image image = System.Drawing.Image.FromFile(imgPath))
            {
                System.Windows.Forms.Clipboard.SetImage(image);
                PostCommand("._pasteclip " + x + "," + y + " ");
                var objId = Autodesk.AutoCAD.Internal.Utils.EntLast();
                SetOleSize(objId, x, y, width, height);
            }
        }

        /// <summary>
        /// 设置old对象的大小和位置
        /// </summary>
        /// <param name="objectId"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        public static void SetOleSize(ObjectId objectId, double x, double y, double width, double height)
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                var ole2Frame = tr.GetObject(objectId, OpenMode.ForWrite) as Ole2Frame;
                if (ole2Frame != null)
                {

                    var lowerLeft = new Point3d(x, y, 0);
                    var lowerRight = new Point3d(x + width, y, 0);
                    var upperLeft = new Point3d(x, y + height, 0);
                    var upperRight = new Point3d(x + width, y + height, 0);

                    ole2Frame.Position3d = new Rectangle3d(upperLeft, upperRight, lowerLeft, lowerRight);
                }
                tr.Commit();
            }
        }

        /// <summary>
        /// 同步发送命令
        /// </summary>
        /// <param name="cmd"></param>
        /// <returns></returns>
        public static bool PostCommand(string cmd)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(cmd))
                    return false;

                var doc = Application.DocumentManager.MdiActiveDocument;
                if (doc == null)
                    return false;
#if ZwCAD
                dynamic acad = Application.ZcadApplication;
                acad.ActiveDocument.SendCommand(cmd);
#else
                dynamic acad = Application.AcadApplication;
                acad.ActiveDocument.SendCommand(cmd);
#endif
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        public static List<Viewport> GetViewportDataInCurrent()
        {
            var result = new List<Viewport>();

            var db = HostApplicationServices.WorkingDatabase;
            using (var trans = db.TransactionManager.StartTransaction())
            {
                var blkRcd = trans.GetObject(db.CurrentSpaceId, OpenMode.ForRead) as BlockTableRecord;
                if (blkRcd == null)
                    return null;

                foreach (var id in blkRcd)
                {
                    if (id.IsErased || !id.IsValid)
                        continue;

                    var obj = UtilFunc.GetObject(trans, id, OpenMode.ForRead);
                    if (obj == null)
                        continue;

                    if (obj is Viewport vp)
                    {
                        if (vp != null)
                            result.Add(vp);
                    }
                }

                trans.Abort();
            }

            return result;
        }

        public static ObjectId SelectEntity(string typeName = "", string message = "")
        {
            var ed = Application.DocumentManager.MdiActiveDocument?.Editor;
            if (ed == null)
                return ObjectId.Null;

            PromptSelectionOptions options = new PromptSelectionOptions();
            options.MessageForAdding = message;

            TypedValue[] tv = new TypedValue[1];
            tv.SetValue(new TypedValue((int)DxfCode.Start, typeName), 0);
            SelectionFilter sf = new SelectionFilter(tv);

            var result = ed.GetSelection(options, sf);
            if (result.Status != PromptStatus.OK)
                return ObjectId.Null;

            return result.Value.GetObjectIds().Last();
        }

        public static List<ObjectId> SelectEntities(string typeName = "", string message = "")
        {
            var ed = Application.DocumentManager.MdiActiveDocument?.Editor;

            PromptSelectionOptions options = new PromptSelectionOptions();
            if (!string.IsNullOrEmpty(message))
                options.MessageForAdding = message;

            TypedValue[] tv = new TypedValue[1];
            tv.SetValue(new TypedValue((int)DxfCode.Start, typeName), 0);
            SelectionFilter sf = new SelectionFilter(tv);

            var result = ed.GetSelection(options, sf);
            if (result.Status != PromptStatus.OK)
                return new List<ObjectId>();

            return result.Value.GetObjectIds().ToList();
        }

        public static void PrintMessage(string message)
        {
            var ed = Application.DocumentManager.MdiActiveDocument?.Editor;
            if (ed != null)
            {
                ed.WriteMessage(message);
            }
        }

        /// <summary>
        /// 获取系统变量
        /// </summary>
        public static object GetSysVar(string varName)
        {
            return Autodesk.AutoCAD.ApplicationServices.Core.Application.GetSystemVariable(varName);
        }

        /// <summary>
        /// 设置系统变量
        /// </summary>
        public static void SetSysVar(string varName, object value)
        {
            Autodesk.AutoCAD.ApplicationServices.Application.SetSystemVariable(varName, value);

            // Autodesk.AutoCAD.ApplicationServices.Application.SetSystemVariable("IMAGEFRAME", Convert.ToInt16(1));
            //Autodesk.AutoCAD.ApplicationServices.Core.Application.SetSystemVariable("IMAGEFRAME", Convert.ToInt16(1));
        }


        public static ObjectId[] WindowSelection(Point3d pt1, Point3d pt2)
        {
            var ed = Application.DocumentManager.MdiActiveDocument?.Editor;
            if (ed != null)
            {
                var result = ed.SelectCrossingWindow(pt1, pt2);
                if (result.Status == Autodesk.AutoCAD.EditorInput.PromptStatus.OK)
                    return result.Value.GetObjectIds();
            }

            return null;
        }


        public static void SelectPoint()
        {
            var ed = Application.DocumentManager.MdiActiveDocument.Editor;
            var ppo = new PromptPointOptions("Select a point");
            var ppr = ed.GetPoint(ppo);
            if (ppr.Status != PromptStatus.OK)
                ed.WriteMessage("Error!");
            else
                ed.WriteMessage("Your select point: " + ppr.Value.ToString());
        }

        public static void GetDistance()
        {
            var ed = Application.DocumentManager.MdiActiveDocument.Editor;
            var pdo = new PromptDistanceOptions("Find distance, select first point:");
            var pdr = ed.GetDistance(pdo);
            if (pdr.Status != PromptStatus.OK)
                ed.WriteMessage("Error!");
            else
                ed.WriteMessage("The distance is: " + pdr.Value.ToString());
        }
    }
}
